/*
 * any.h
 *
 *  Created on: 2008-10-9
 *      Author: fanliangliang
 */

#ifndef ANY_H_
#define ANY_H_

#include "config.h"
#include <algorithm>
#include <typeinfo>
#include <iostream>
#include <sstream>
#include <cstring>
#include <string>

BEGIN_NAMESPACE_TOXIC

namespace detail {

	inline size_t width(bool b) {
		return b ? 4 : 5;
	}

	inline size_t width(const char* str) {
		return strlen(str);
	}

	inline size_t width(const std::string& str) {
		return str.size();
	}

	template <typename T>
	inline size_t width(T value) {
		std::ostringstream oss;
		oss << value;
		return oss.str().size();
	}


	class placeholder {
	public:
		virtual ~placeholder() {
		}

	public:
		virtual const std::type_info& type() const = 0;
		virtual placeholder* clone() const = 0;
		virtual size_t width() const = 0;
		virtual std::ostream& print(std::ostream& ostrm) const = 0;
	};

	template <typename ValueType>
	class holder: public placeholder {
	public:
		holder(const ValueType& value)
		:held(value) {
		}

	public:
		virtual const std::type_info& type() const {
			return typeid(ValueType);
		}

		virtual placeholder* clone() const {
			return new holder(held);
		}

		virtual size_t width() const {
			return detail::width(held);
		}

		virtual std::ostream& print(std::ostream& ostrm) const {
			return ostrm << std::boolalpha << held << std::noboolalpha;
		}

	public:
		ValueType held;
	};

} // namespace detail


class any {
public:
	any()
	:content(0) {
	}

	template <typename ValueType>
	any(const ValueType& value)
	:content(new detail::holder<ValueType>(value)) {
	}

	any(const any& other)
	:content(other.content ? other.content->clone() : 0) {
	}

	~any() {
		delete content;
	}

	any& swap(any& rhs) {
		std::swap(content, rhs.content);
		return *this;
	}

	template <typename ValueType>
	any& operator=(const ValueType& rhs) {
		any(rhs).swap(*this);
		return *this;
	}

	any& operator=(const any& rhs) {
		any(rhs).swap(*this);
		return *this;
	}

	bool empty() const {
		return !content;
	}

	const std::type_info& type() const {
		return content ? content->type() : typeid(void);
	}

	size_t width() const {
		return content ? content->width() : 0;
	}

	std::ostream& print(std::ostream& ostrm) const {
		return content ? content->print(ostrm) : ostrm;
	}

private:
	template <typename ValueType>
	friend ValueType* any_cast(any*);

private:
	detail::placeholder* content;
};


class bad_any_cast: public std::bad_cast {
public:
	virtual const char* what() const throw() {
		return "bad_any_cast: failed conversion using any_cast";
	}
};


template <typename ValueType>
ValueType* any_cast(any* operand) {
	return operand && operand->type() == typeid(ValueType)
	? &static_cast<detail::holder<ValueType>*>(operand->content)->held : 0;
}

template <typename ValueType>
inline const ValueType* any_cast(const any* operand) {
	return any_cast<ValueType>(const_cast<any*>(operand));
}

template <typename ValueType>
ValueType& any_cast(any& operand) {
	ValueType* result = any_cast<ValueType>(&operand);
	if (!result) {
		throw bad_any_cast();
	}
	return *result;
}

template <typename ValueType>
inline const ValueType& any_cast(const any& operand) {
	return any_cast<ValueType>(const_cast<any&>(operand));
}

END_NAMESPACE_TOXIC

#endif /* ANY_H_ */
